/*
 * BlackLightning.PluginLib.Modules.IObject
 * Andy Tidball
 * 
 * Project: Black Lightning Plugin Library
 * Copyright: GNU General Public License
 */

using System;

namespace BlackLightning.PluginLib {
	/// <summary>
	/// Defines the interface between Black Lightning and anything that can send and receive messages.
	/// </summary>
	public interface IMessageHandler {
		/// <summary>
		/// Raised by the IObject to send a Message to Black Lightning.
		/// </summary>
		event SendMessageEventHandler SendMessage;

		/// <summary>
		/// Called by Black Lightning to send a Message to the IObject.
		/// </summary>
		/// <param name="Message">The Message being sent to the IObject.</param>
		void HandleMessage(Message Message);
	}
	
	/// <summary>
	/// The prototype for the SendMessage event.
	/// </summary>
	/// <param name="Sender">The IModule which sent the message.</param>
	/// <param name="e">Arguments about the message being sent.</param>
	public delegate void SendMessageEventHandler(object Sender, SendMessageEventArgs e);

	/// <summary>
	/// The arguments sent with a SendMessage event.
	/// </summary>
	[Serializable]
	public class SendMessageEventArgs : EventArgs {
		// member data
		private Message _Message; // the message being sent

		/// <summary>
		/// Creates a new SendMessageEventArgs.
		/// </summary>
		/// <param name="Message">The message to be sent.</param>
		public SendMessageEventArgs(Message Message) {
			_Message = Message;
		}

		/// <summary>
		/// Gets the message being sent.
		/// </summary>
		public Message Message {
			get {
				return _Message;
			}
		}
	}

	/// <summary>
	/// A helper class that implements IMessageHandler and provides helper functionality to derived classes.
	/// </summary>
	public abstract class MessageHandler : IMessageHandler {
		/// <summary>
		/// Fired whenever the Module has a Message for Black Lightning.
		/// </summary>
		public event SendMessageEventHandler SendMessage;

		/// <summary>
		/// Fires the SendMessage event.
		/// </summary>
		/// <param name="e">Arguments to pass with the SendMessage event.</param>
		protected void OnSendMessage(SendMessageEventArgs e) {
			if (SendMessage != null) {
				SendMessage(this, e);
			}
		}

		/// <summary>
		/// Wraps the given Message in SendMessageEventArgs and fires the SendMessage event.
		/// </summary>
		/// <param name="M">The Message to send.</param>
		protected void Send(Message M) {
			OnSendMessage(new SendMessageEventArgs(M));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category, Hidden));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, EncryptKey));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		/// <param name="Editor">The UITypeEditor-derived type to use as a UI editor for the option's type.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey, Type Editor) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, EncryptKey, Editor));
		}

		/// <summary>
		/// Creates a RegisterOptionMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		/// <param name="Editor">The UITypeEditor-derived type to use as a UI editor for the option's type.</param>
		/// <param name="Converter">The TypeConverter-derived type to use to convert the option's values to and from strings.</param>
		protected void RegisterOption(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey, Type Editor, Type Converter) {
			Send(new RegisterOptionMessage(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, EncryptKey, Editor, Converter));
		}

		/// <summary>
		/// Wraps the given name in an UnregisterOptionMessage and sends it.
		/// </summary>
		/// <param name="Name">The name of the option to unregister.</param>
		protected void UnregisterOption(string Name) {
			Send(new UnregisterOptionMessage(Name));
		}

		/// <summary>
		/// Wraps the given name and value in a ChangeOptionValueMessage and sends it.
		/// </summary>
		/// <param name="Name">The name of the option to change the value of.</param>
		/// <param name="Value">The value to change the option's value to.</param>
		protected void ChangeOptionValue(string Name, object Value) {
			Send(new ChangeOptionValueMessage(Name, Value));
		}

		/// <summary>
		/// Sends a ShowOptionsMessage to Black Lightning to display the options dialog.
		/// </summary>
		protected void ShowOptions() {
			Send(new ShowOptionsMessage());
		}

		/// <summary>
		/// Registers a timer that fires once at the given time.
		/// </summary>
		/// <param name="ID">An ID that's meaningful (and unique) to the owning module.</param>
		/// <param name="Start">The time that the timer should fire.</param>
		protected void RegisterTimer(int ID, DateTime Start) {
			Send(new RegisterTimerMessage(ID, Start));
		}

		/// <summary>
		/// Registers a timer that starts immediately and repeats indefinitely.
		/// </summary>
		/// <param name="ID">An ID that's meaningful (and unique) to the owning module.</param>
		/// <param name="Interval">The number of milliseconds between the timer's repeating expirations.</param>
		protected void RegisterTimer(int ID, int Interval) {
			Send(new RegisterTimerMessage(ID, Interval));
		}

		/// <summary>
		/// Registers a timer that starts immediately and repeats a given number of times.
		/// </summary>
		/// <param name="ID">An ID that's meaningful (and unique) to the owning module.</param>
		/// <param name="ExpireCount">The number of times that the timer will expire, or 0 to repeat indefinitely.</param>
		/// <param name="Interval">The number of milliseconds between the timer's repeating expirations.</param>
		protected void RegisterTimer(int ID, int ExpireCount, int Interval) {
			Send(new RegisterTimerMessage(ID, ExpireCount, Interval));
		}

		/// <summary>
		/// Registers a timer that starts at the given time and repeats indefinitely.
		/// </summary>
		/// <param name="ID">An ID that's meaningful (and unique) to the owning module.</param>
		/// <param name="Start">The time that the timer should first expire.</param>
		/// <param name="Interval">The number of milliseconds between the timer's repeating expirations.</param>
		protected void RegisterTimer(int ID, DateTime Start, int Interval) {
			Send(new RegisterTimerMessage(ID, Start, Interval));
		}

		/// <summary>
		/// Registers a timer that starts at the given time and repeats a given number of times.
		/// </summary>
		/// <param name="ID">An ID that's meaningful (and unique) to the owning module.</param>
		/// <param name="Start">The time that the timer should first expire.</param>
		/// <param name="ExpireCount">The number of times that the timer will expire, or 0 to repeat indefinitely.</param>
		/// <param name="Interval">The number of milliseconds between the timer's repeating expirations.</param>
		protected void RegisterTimer(int ID, DateTime Start, int ExpireCount, int Interval) {
			Send(new RegisterTimerMessage(ID, Start, ExpireCount, Interval));
		}

		/// <summary>
		/// Creates an UnregisterTimerMessage with the given parameters and sends it.
		/// </summary>
		/// <param name="ID">The ID of the timer to unregister.</param>
		protected void UnregisterTimer(int ID) {
			Send(new UnregisterTimerMessage(ID));
		}

		/// <summary>
		/// Called when Black Lightning has a Message specifically for this Module.
		/// </summary>
		/// <param name="Message">The Message being delivered to the Module.</param>
		public abstract void HandleMessage(Message Message);
	}
}
